package org.dubnation.user.service.impl;

import org.dubnation.base.constants.SystemConstants;
import org.dubnation.base.enums.ResponseCode;
import org.dubnation.base.exception.BusinessException;
import org.dubnation.base.util.audit.DubnationAssert;
import org.dubnation.base.util.encryption.MD5Utils;
import org.dubnation.user.domain.LoginInfo;
import org.dubnation.user.domain.dto.UerRegisterDTO;
import org.dubnation.user.domain.User;
import org.dubnation.user.mapper.LoginInfoMapper;
import org.dubnation.user.mapper.UserMapper;
import org.dubnation.user.rabbitmq.config.RegisterNoticeRabbitmqConfig;
import org.dubnation.user.rabbitmq.entity.SendEntity;
import org.dubnation.user.service.IUserService;
import org.dubnation.base.service.impl.BaseServiceImpl;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author zhu
 * @since 2023-11-09
 */
@Service
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public class UserServiceImpl extends BaseServiceImpl<User> implements IUserService {

    @Autowired
    private RedisTemplate<Object, Object> redisTemplate;

    @Autowired(required = false)
    private LoginInfoMapper loginInfoMapper;

    @Autowired(required = false)
    private UserMapper userMapper;

    @Autowired
    private LoginInfo loginInfos;

    @Autowired
    private RabbitTemplate rabbitTemplate;

    @Autowired
    private SendEntity sendEntity;

    @Value("${to-car-list-url}")
    private String toCarListUrl;

    @Value("${spring.mail.username}")
    private String senderEmail;

    private static User user;
    //注入set方法，实现static与Autowired同时满足
    @Autowired
    public void setUser(User user) {
        UserServiceImpl.user = user;
    }


    /**
     * 用户注册
     * @param uerRegisterDTO
     */
    @Override
    @Transactional
    public void userRegister(UerRegisterDTO uerRegisterDTO) {
        //1.检查手机验证码类型是否正确
        String codeType = uerRegisterDTO.getCodeType();
        DubnationAssert.isEq(codeType, SystemConstants.REDIS_CODE_REGISTER, ResponseCode.RESPONSE_CODE_500);
        //2.验证两次密码是否一致
        DubnationAssert.isEq(uerRegisterDTO.getPassword(), uerRegisterDTO.getConfirmPassword(), ResponseCode.RESPONSE_CODE_400001);
        //3.检验手机验证码
        Object phoneCodeInRedis = redisTemplate.opsForValue().get(uerRegisterDTO.getPhone() + ":" + SystemConstants.REDIS_CODE_REGISTER);
        if (Objects.nonNull(phoneCodeInRedis)){
            String phoneCode = phoneCodeInRedis.toString().split(":")[0];
            DubnationAssert.isEq(phoneCode, uerRegisterDTO.getPhoneCode(), ResponseCode.RESPONSE_CODE_4000015);
        }
        //4.校验用户名和邮箱唯一性 (用户名和邮箱都不能重复)
        Integer userCount = userMapper.getByUsernameOrEmail(uerRegisterDTO.getUsername(), uerRegisterDTO.getEmail());
        if (userCount > 0){
            throw new BusinessException(ResponseCode.RESPONSE_CODE_4000027);
        }
        User user = convertUser(uerRegisterDTO);
        //5.注册信息表入库--phone,salt,password,type,disable
        BeanUtils.copyProperties(user, loginInfos); //将用户信息拷贝到登陆注册信息中
        if (uerRegisterDTO.getCodeType().equals(SystemConstants.REDIS_CODE_REGISTER)){
            loginInfos.setType(LoginInfo.TYPE_USER);
        }
        loginInfos.setDisable(LoginInfo.DISABLE_AVAILABLE);
        loginInfoMapper.insert(loginInfos);
        //6.用户数据入库--phone,salt,password,state,createtime
        user.setLogininfoId(loginInfos.getId());
        userMapper.insert(user);
        //7.发送短信提醒用户注册成功-使用rabbitmq暂存
        sendEntity.setFrom(senderEmail);
        sendEntity.setTo(uerRegisterDTO.getEmail());
        sendEntity.setSubject("恭喜您注册成功, 当前车辆正在降价热销中, 您可以点击点击以下链接进一步了解: ");
        sendEntity.setContent(String.format("<a href=%s>%s</a>", toCarListUrl, toCarListUrl));
        //将发送邮件通知存储到mq中
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM, "inform.email", sendEntity);
        //将发送短信通知存储到mq中
        sendEntity.setFrom(null);
        sendEntity.setTo(uerRegisterDTO.getPhone());
        URI listUrl = null;
        try {
            //将字串转换为链接地址
            listUrl = (new URL(toCarListUrl)).toURI();
        } catch (URISyntaxException e) {
            e.printStackTrace();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        }
        String smsContent = "恭喜用户%s注册成功, 当前车辆正在降价热销中, 您可以点击链接%s进一步了解哦!";
        sendEntity.setContent(String.format(smsContent, uerRegisterDTO.getUsername(), listUrl));
        sendEntity.setSubject(null);
        rabbitTemplate.convertAndSend(RegisterNoticeRabbitmqConfig.EXCHANGE_TOPICS_INFORM, "inform.sms", sendEntity);
        //8.注册成功之后将redis中的手机验证码删除
        redisTemplate.delete(uerRegisterDTO.getPhone() + ":" + uerRegisterDTO.getCodeType());
    }

    /**
     * 由前端传递的dto生成User数据
     * @param uerRegisterDTO
     * @return
     */
    public static User convertUser(UerRegisterDTO uerRegisterDTO) {
        //非对称算法：加密和解密使用的不是同一对密钥--RSA算法
        //不可逆算法：密码一旦加密就不能解密--MD5算法
        //加盐、迭代：加盐--在原始密码前面加一个随机字符串；迭代--将加盐后密码循环加密多次
        user.setPhone(uerRegisterDTO.getPhone());
        user.setUsername(uerRegisterDTO.getUsername());
        user.setEmail(uerRegisterDTO.getEmail());
        String salt = UUID.randomUUID().toString();
        user.setSalt(salt); //盐值是随机数
        String password = MD5Utils.encryptionByMd5("kisc1130" + salt + uerRegisterDTO.getPassword()); //对密码进行加盐加密
        user.setPassword(password);
        user.setState(User.ACTIVATED);
        user.setCreatetime(new Date());
        return user;
    }

    /**
     * 获取用户的权限
     * @param id
     * @return
     */
    @Override
    public List<String> getPermissionSn(Long id) {
        return userMapper.getPermissionSn(id);
    }
}
